Ext.ns('Ext.ux.form');

Ext.ux.form.LovCombo = Ext.extend(Ext.form.ComboBox, {
    triggerAction: 'all',
    mode: 'local',
    checkField: 'checked',
    separator: ',',
    hideOnSelect: false,
    beforeBlur: Ext.emptyFn,
    initComponent: function(){
        if (!this.tpl) {
            this.tpl = '<tpl for=".">' +
            '<div class="x-combo-list-item">' +
            '<img src="' +
            Ext.BLANK_IMAGE_URL +
            '" ' +
            'class="ux-lovcombo-icon ux-lovcombo-icon-' +
            '{[values.' +
            this.checkField +
            '?"checked":"unchecked"' +
            ']}">' +
            '<div class="ux-lovcombo-item-text">{' +
            (this.displayField || 'text') +
            '}</div>' +
            '</div>' +
            '</tpl>';
        }
        if (this.ds instanceof Ext.data.Store) {
            this.store = this.ds;
            delete this.ds;
        }
        else 
            if (this.ds.call) {
                this.mode = 'remote';
                this.store = new Bee.data.DWRStore({
                    dwr: {
                        call: this.ds.call,
                        params: this.ds.params
                    },
                    listeners: this.ds.listeners || null,
                    fields: this.fields,
                    defaultItems: this.defaultItems
                });
                delete this.ds;
            }
            else {
                this.store = new Ext.data.SimpleStore({
                    data: this.ds.data,
                    fields: this.ds.fields ||
                    ['key', 'label']
                });
                delete this.ds;
            }
        // call parent
        Ext.ux.form.LovCombo.superclass.initComponent.apply(this, arguments);
        // install internal event handlers
        this.on({
            scope: this,
            beforequery: this.onBeforeQuery,
            blur: this.onRealBlur
        });
        // remove selection from input field
        this.onLoad = this.onLoad.createSequence(function(){
            if (this.el) {
                var v = this.el.dom.value;
                this.el.dom.value = '';
                this.el.dom.value = v;
            }
        });
    },
    initEvents: function(){
        Ext.ux.form.LovCombo.superclass.initEvents.apply(this, arguments);
        // disable default tab handling - does no good
        this.keyNav.tab = false;
    },
    clearValue: function(){
        this.value = '';
        this.setRawValue(this.value);
        this.store.clearFilter();
        this.store.each(function(r){
            r.set(this.checkField, false);
        }, this);
        if (this.hiddenField) {
            this.hiddenField.value = '';
        }
        this.applyEmptyText();
    },
    getCheckedDisplay: function(){
        var re = new RegExp(this.separator, "g");
        var va = this.getCheckedValue(this.displayField).replace(re, this.separator + ' ');
        return va
    },
    getCheckedValue: function(field){
        field = field || this.valueField;
        var c = [];
        // store may be filtered so get all records
        var snapshot = this.store.snapshot || this.store.data;
        snapshot.each(function(r){
            if (r.get(this.checkField)) {
                c.push(r.get(field));
            }
        }, this);
        return c.join(this.separator);
    },
    onBeforeQuery: function(qe){
        qe.query = qe.query.replace(new RegExp(this.getCheckedDisplay() + '[ ' + this.separator + ']*'), '');
    },
    onRealBlur: function(){
        this.list.hide();
        var rv = this.getRawValue();
        var rva = rv.split(new RegExp(RegExp.escape(this.separator) + ' *'));
        var va = [];
        var snapshot = this.store.snapshot || this.store.data;
        // iterate through raw values and records and check/uncheck items
        Ext.each(rva, function(v){
            snapshot.each(function(r){
                if (v === r.get(this.displayField)) {
                    va.push(r.get(this.valueField));
                }
            }, this);
        }, this);
        this.setValue(va.join(this.separator));
        this.store.clearFilter();
    },
    onSelect: function(record, index){
        if (this.fireEvent('beforeselect', this, record, index) !== false) {
            // toggle checked field
            record.set(this.checkField, !record.get(this.checkField));
            // display full list
            if (this.store.isFiltered()) {
                this.doQuery(this.allQuery);
            }
            // set (update) value and fire event
            this.setValue(this.getCheckedValue());
            this.fireEvent('select', this, record, index);
        }
    },
    setValue: function(v){
        if (v) {
            v = '' + v;
            if (this.valueField) {
                this.store.clearFilter();
                this.store.each(function(r){
                    var checked = !(!v.match('(^|' + this.separator + ')' + RegExp.escape(r.get(this.valueField)) +
                    '(' +
                    this.separator +
                    '|$)'));
                    
                    r.set(this.checkField, checked);
                }, this);
                this.value = this.getCheckedValue();
                this.setRawValue(this.getCheckedDisplay());
                if (this.hiddenField) {
                    this.hiddenField.value = this.value;
                }
            }
            else {
                this.value = v;
                this.setRawValue(v);
                if (this.hiddenField) {
                    this.hiddenField.value = v;
                }
            }
            if (this.el) {
                this.el.removeClass(this.emptyClass);
            }
        }
        else {
            this.clearValue();
        }
    },
    selectAll: function(){
        this.store.each(function(record){
            // toggle checked field
            record.set(this.checkField, true);
        }, this);
        
        //display full list
        this.doQuery(this.allQuery);
        this.setValue(this.getCheckedValue());
    },
    deselectAll: function(){
        this.clearValue();
    },
    onRender: function(ct, position){
        Ext.ux.form.LovCombo.superclass.onRender.call(this, ct, position);
        if (this.mode == 'remote') {
            if (!this.lazyInit) {
                this.doQuery(this.allQuery, true);
            }
            this.store.on('load', function(){
                if (this.getValue()) {
                    this.setValue(this.getValue());
                }
            }, this);
        }
    }
});

Ext.reg('lovcombo', Ext.ux.form.LovCombo);
